package com.java.base.exercise.limitrate;

import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author RenPu
 * @Date 2023/3/17 16:04
 * @Version 1.0
 * @Description: 基于令牌桶完成限流的实现
 *               优点：能将请求均匀分发到时间区间内，同时还能接受服务器突发请求
 *               缺点：牺牲小部分流量
 **/
public class GuavaRateLimiter {

    //令牌存储容器
    private static final Map<String, RateLimiter> tokenContainer=Maps.newConcurrentMap();


    //设定限流规则
    static {
        createRateLimiterRule("order",50);
    }

    private static void createRateLimiterRule(String resouce, int qps) {

        if(tokenContainer.containsKey(resouce)){
            tokenContainer.get(resouce).setRate(qps);
        }else {

            //每秒50个，2秒后达到正常速率
            RateLimiter rateLimiter = RateLimiter.create(qps, 1000, TimeUnit.MILLISECONDS);
            tokenContainer.putIfAbsent(resouce,rateLimiter);

        }
    }

    public static void main(String[] args) throws InterruptedException {


        /**===============令牌桶限流算法的实现==============**/


//        for (int i = 0; i <500 ; i++) {
//
//            new Thread(()->{
//
//                if(tokenContainer.get("order").tryAcquire()){
//                    System.out.println("开始正常执行业务逻辑=====================");
//                }else {
//                    System.out.println("触发限流。。。。。");
//                }
//            }).start();
//
//        }

//
//        /**============平滑突发限流======允许突发请求，后面慢慢的趋于平稳==================**/
//        RateLimiter rateLimiter = RateLimiter.create(5);
//
//        while (true){
//            System.out.println(rateLimiter.acquire());
//        }


        /**============平滑预热限流=======先试探性的慢慢的增大请求量，最后趋于平稳=================**/

        //每秒新增的令牌数，速率由预热到平稳所需要的耗时

        RateLimiter rateLimiter1 = RateLimiter.create(5, 1000L, TimeUnit.MILLISECONDS);

        for (int i = 0; i <5 ; i++) {
            System.out.println(rateLimiter1.acquire());
        }

        Thread.sleep(1000L);
        for (int i = 0; i <50 ; i++) {
            System.out.println(rateLimiter1.acquire());
        }




    }






}
